import { CtlBase } from './CtlBase'
import { CtlBpmnDefault } from './CtlDefaultValue'
import { parseYvanPropChangeVJson } from './CtlUtils'
import { YvEvent, YvEventDispatch } from './YvanEvent'
import webix from 'webix'

webix.protoUI(
    {
        name: 'bpmn',
        defaults: {},
        $init: function (config: any) {
            this._domid = 'dd' + webix.uid();
            this.$view.innerHTML = `<div id='${this._domid}' style='width:100%;height:100%;'></div>`
            this.$ready.push(this._ready)
            _.extend(this.config, config)
            if (config.on && typeof config.on.onInited === 'function') {
                config.on.onInited.call(this)
            }
        },
        _ready: function (this: any) {
            this.isBpmnLoad = false;
            this.myDebounce = _.debounce(() => {
                this._updateScrollSize()
            })
        },
        _set_inner_size: function () {
            if (!this._bpmn || !this.$width) return

            this.myDebounce()
        },
        destructor: function () {
            if (this.$destructed) {
                return;
            }

            this.$destructed = true;
            if (this.config.on && typeof this.config.on.onDestruct === 'function') {
                this.config.on.onDestruct.call(this)
            }
        },
        _updateScrollSize: function () {
            console.log('_updateScrollSize')
            var box = this._bpmn._container;
            box.style.height = (this.$height || 0) + 'px'
            box.style.width = (this.$width || 0) + 'px'

            var canvas = this._bpmn.get('canvas')
            // _.debounce(() => {
            canvas.zoom('fit-viewport')
            // })
        },
        $setSize: function (x: any, y: any) {
            if (webix.ui.view.prototype.$setSize.call(this, x, y)) {
                _.defer(() => {
                    this._set_inner_size()
                    if (this.isBpmnLoad == false) {
                        this.isBpmnLoad = true
                        //@ts-ignore
                        require(['bpmn-modeler', 'bpmn-navigated', 'bpmn-viewer'], (BpModeler: any, BpNavigated: any, BpmnViewer: any) => {
                            const $dom = $('#' + this._domid)
                            const bpmn = new BpNavigated({
                                container: $dom[0],
                                ...this.config.bpmnConfig
                            });
                            this._bpmn = bpmn;
                            if (this.wrapper._todoDiagram) {
                                this.wrapper.openDiagram(this.wrapper._todoDiagram);
                                delete this.wrapper._todoDiagram
                            }
                            const eventBus = bpmn.get('eventBus');
                            if (this.wrapper.onHover) {
                                eventBus.on('element.hover', (e: any) => {
                                    YvEventDispatch(this.wrapper.onHover, this.wrapper, e.element);
                                })
                            }
                            if (this.wrapper.onOut) {
                                eventBus.on('element.out', (e: any) => {
                                    YvEventDispatch(this.wrapper.onOut, this.wrapper, e.element);
                                })
                            }
                            if (this.wrapper.onClick) {
                                eventBus.on('element.click', (e: any) => {
                                    YvEventDispatch(this.wrapper.onClick, this.wrapper, e.element);
                                })
                            }
                            if (this.wrapper.onDblClick) {
                                eventBus.on('element.dblclick', (e: any) => {
                                    YvEventDispatch(this.wrapper.onDblClick, this.wrapper, e.element);
                                })
                            }
                            if (this.wrapper.onMousedown) {
                                eventBus.on('element.mousedown', (e: any) => {
                                    YvEventDispatch(this.wrapper.onMousedown, this.wrapper, e.element);
                                })
                            }
                            if (this.wrapper.onMouseup) {
                                eventBus.on('element.mouseup', (e: any) => {
                                    YvEventDispatch(this.wrapper.onMouseup, this.wrapper, e.element);
                                })
                            }
                        })
                    }
                })
            }
        }
    },
    webix.ui.view
)

export class CtlBpmn extends CtlBase<CtlBpmn> {
    static create(module: any, vjson: any): CtlBpmn {
        const that = new CtlBpmn(vjson)
        that._module = module

        _.defaultsDeep(vjson, CtlBpmnDefault)

        const yvanProp = parseYvanPropChangeVJson(vjson, [
            'value',
            'onSuccess',
            'onFailed',
            'onHover',
            'onOut',
            'onClick',
            'onDblClick',
            'onMousedown',
            'onMouseup'
        ])

        // 将 vjson 存至 _webixConfig
        that._webixConfig = vjson

        // 将 yvanProp 合并至当前 Ctl 对象, 期间会操作 _webixConfig
        _.assign(that, yvanProp)

        // 将 事件与 _webixConfig 一起存至 vjson 交给 webix 框架做渲染
        _.merge(vjson, that._webixConfig, {
            on: {
                onInited(this: any) {
                    that.attachHandle(this, { ...vjson, ...yvanProp })
                    this.wrapper = that
                },
                onDestruct(this: any) {
                    that.removeHandle()
                }
            }
        })
        return that
    }

    /**
     * 图形加载完毕
     */
    onSuccess?: YvEvent<CtlBpmn, any>

    /**
     * 图形加载失败
     */
    onFailed?: YvEvent<CtlBpmn, any>

    /**
     * 事件
     */
    onHover?: YvEvent<CtlBpmn, any>

    onOut?: YvEvent<CtlBpmn, any>

    onClick?: YvEvent<CtlBpmn, any>

    onDblClick?: YvEvent<CtlBpmn, any>

    onMousedown?: YvEvent<CtlBpmn, any>

    onMouseup?: YvEvent<CtlBpmn, any>

    /**
     * 获取bpmn
     */
    get bpmn(): any {
        return this._webix._bpmn
    }

    get bpmnCanvas(): any {
        return this.bpmn.get('canvas');
    }

    get bpmnOverlays(): any {
        return this.bpmn.get('overlays');
    }

    get bpmnZoomScroll(): any {
        return this.bpmn.get('zoomScroll');
    }

    handleZoomBig() {
        this.bpmnZoomScroll.stepZoom(1);
    }

    handleZoomSmall() {
        this.bpmnZoomScroll.stepZoom(-1);
    }

    handleZoomReset() {
        this.bpmnZoomScroll.reset();
    }

    openDiagram(diagram: string) {
        if (!this.bpmn) {
            this._todoDiagram = diagram
            return;
        }
        this.bpmn.importXML(diagram, (err: any) => {
            if (err) {
                if (this.onFailed) {
                    YvEventDispatch(this.onFailed, this, undefined);
                }
                return console.error('could not import BPMN 2.0 diagram', err);
            }
            // zoom to fit full viewport
            this.bpmnCanvas.zoom('fit-viewport');
            if (this.onSuccess) {
                YvEventDispatch(this.onSuccess, this, undefined);
            }
        });
    }

    /*********************** 私有变量 **********************/
    private _todoDiagram?: string
}
